package com.loadagent.core;

import com.loadagent.core.util.*;
import org.apache.commons.io.FileUtils;

import java.io.*;

public class JarDecryptor
{
    private static final JarDecryptor single;
    private char[] code;
    private static final String ENCRYPT_PATH = "META-INF/.classes/";

    public static JarDecryptor getInstance() {
        return JarDecryptor.single;
    }

    public JarDecryptor() {
        this.code = SysUtils.makeMarchinCode();
    }

    public byte[] doDecrypt(final String projectPath, final String fileName, char[] password) {
        final long t1 = System.currentTimeMillis();
        final File workDir = new File(projectPath);
        byte[] bytes = readEncryptedFile(workDir, fileName);
        if (bytes == null) {
            return null;
        }
        final byte[] codeBytes = readEncryptedFile(workDir, "org.springframework.config.Code");
        if (codeBytes != null) {
            if (!StrUtils.equal(EncryptUtils.md5(this.code), StrUtils.toChars(codeBytes))) {
                System.out.println("该项目不可在此机器上运行!\n");
                System.exit(-1);
            }
            final char[] pass = StrUtils.merger(new char[][] { fileName.toCharArray(), this.code });
            bytes = EncryptUtils.de(bytes, pass, 1);
        }
        if (password.length == 1 && password[0] == '#') {
            password = readPassFromJar(workDir);
        }
        final char[] pass = StrUtils.merger(new char[][] { password, fileName.toCharArray() });
        bytes = EncryptUtils.de(bytes, pass, 1);
        final long t2 = System.currentTimeMillis();
        return bytes;
    }

    public void createFolder(String path) {
        File folder = new File(path);
        // 检查文件夹是否存在
        if (!folder.exists()) {
            // 递归创建父文件夹
            createFolder(folder.getParent());

            // 创建当前文件夹
            folder.mkdir();
        }
    }

    //反编译出来源代码
    public void findRealClass(String fileDir, String dictDir, char[] password){
        File folder = new File(fileDir+"/META-INF/.classes/");
        if (folder.exists() && folder.isDirectory()) {

            //创建目标文件夹
            createFolder(dictDir);
            File[] files = folder.listFiles();
            // 遍历文件数组
            for (File file : files) {
                // 输出文件名
                System.out.println(file.getName());
                byte[] classFileBytes = doDecrypt(fileDir,
                        file.getName(),password);

                try {
                    FileUtils.writeByteArrayToFile(new File(dictDir+File.separator+file.getName()
                        +".class"),classFileBytes);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        } else {
            System.out.println("源文件夹不存在或不是一个文件夹。");
        }
    }

    public static void main(String args[]){

        JarDecryptor jarDecryptor = new JarDecryptor();
        /*byte[] bytes1 = jarDecryptor.doDecrypt("C:\\Users\\ccc520\\Desktop\\ysy-tz-mes\\ysy-tz-core-1.0-SNAPSHOT",
                "com.ysy.tz.core.annotation.Service",new char[]{'#'});

        try {
            FileUtils.writeByteArrayToFile(new File("d:\\aa.class"),bytes1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }*/

        jarDecryptor.findRealClass("C:\\Users\\ccc520\\Desktop\\ysy-tz-mes\\ysy-tz-core-1.0-SNAPSHOT",
                "C:\\Users\\ccc520\\Desktop\\ysy-tz-mes\\ysy-tz-core-1.0-SNAPSHOT\\class",new char[]{'#'});
    }

    public static byte[] readEncryptedFile(final File workDir, final String name) {
        byte[] bytes = null;
        final String fileName = "META-INF/.classes/" + name;
        if (workDir.isFile()) {
            bytes = JarUtils.getFileFromJar(workDir, fileName);
        }
        else {
            final File file = new File(workDir, fileName);
            if (file.exists()) {
                bytes = IoUtils.readFileToByte(file);
            }
        }
        return bytes;
    }

    public static char[] readPassFromJar(final File workDir) {
        final byte[] passbyte = readEncryptedFile(workDir, "org.springframework.config.Pass");
        if (passbyte != null) {
            final char[] pass = StrUtils.toChars(passbyte);
            return EncryptUtils.md5(pass);
        }
        return null;
    }

    public InputStream decryptConfigFile(final String path, final InputStream in, final char[] pass) {
        if (path.endsWith(".class")) {
            return in;
        }
        final String projectPath = JarUtils.getRootPath(null);
        if (StrUtils.isEmpty(projectPath)) {
            return in;
        }
        byte[] bytes = null;
        try {
            bytes = IoUtils.toBytes(in);
        }
        catch (Exception ex) {}
        if (bytes == null || bytes.length == 0) {
            bytes = this.doDecrypt(projectPath, path, pass);
        }
        if (bytes == null) {
            return in;
        }
        return new ByteArrayInputStream(bytes);
    }

    static {
        single = new JarDecryptor();
    }
}
